package com.tianque.scgrid.service.record.util;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianque.doraemon.mybatis.base.BaseDomain;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * ES 请求工具类
 *
 * @author LiRui
 * @version 1.0
 */
public class ESClientUtil {

    /**
     * 唯一创建方式
     *
     * @param restHighLevelClient
     * @return
     */
    public static ESClientUtil NEW(RestHighLevelClient restHighLevelClient) {
        return new ESClientUtil(restHighLevelClient);
    }

    private final RestHighLevelClient restHighLevelClient;

    private ESClientUtil(RestHighLevelClient restHighLevelClient) {
        this.restHighLevelClient = restHighLevelClient;
    }

    /**
     * 获取ES信息
     *
     * @throws IOException
     */
    public SearchResponse getEsInfo() throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // SearchRequest
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.source(searchSourceBuilder);
        // 查询ES
        return restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    }

    /**
     * 列表查询
     *
     * @param page      页
     * @param rows      行数
     * @param condition eq条件
     * @param order     排序字段
     * @param sort      排序规则
     * @param clazz     返回类型
     * @throws
     */
    public <T> IPage<T> page(Integer page,
                             Integer rows,
                             Map<String, String> condition,
                             String order,
                             SortOrder sort,
                             Class<T> clazz) throws IOException {
        return this.page(page, rows, condition, order, sort, clazz);
    }

    /**
     * 列表查询
     *
     * @param page      页
     * @param rows      行数
     * @param condition eq条件
     * @param order     排序字段
     * @param sort      排序规则
     * @param clazz     返回类型
     * @throws
     */
    public <T> IPage<T> page(Integer page,
                             Integer rows,
                             Map<String, String> condition,
                             String order,
                             SortOrder sort,
                             String index,
                             Class<T> clazz) throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 分页采用简单的from + size分页，适用数据量小的，了解更多分页方式可自行查阅资料
        searchSourceBuilder.from((page - 1) * rows);
        searchSourceBuilder.size(rows);
        // 查询条件，只有查询关键字不为空才带查询条件
        if (Objects.nonNull(condition) && !condition.isEmpty()) {
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
            condition.forEach((k, v) -> queryBuilder.must(QueryBuilders.termQuery(k, v)));
            searchSourceBuilder.query(queryBuilder);
        }
        // 排序
        if (StringUtils.isNotBlank(order) && Objects.nonNull(sort)) {
            searchSourceBuilder.sort(order, sort);
        }
        // SearchRequest
        SearchRequest searchRequest = new SearchRequest();
        if (StringUtils.isNotBlank(index)){
            searchRequest.indices(index);
        }
        searchRequest.source(searchSourceBuilder);
        // 查询ES
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = searchResponse.getHits();
        // 获取总数
        Long total = hits.getTotalHits().value;
        // 遍历封装列表对象
        List<T> bookDtoList = new ArrayList<>();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            bookDtoList.add(JSON.parseObject(searchHit.getSourceAsString(), clazz));
        }
        final Page<T> IPage = new Page<>(page, rows, total);
        IPage.setRecords(bookDtoList);
        return IPage;
    }

    /**
     * 列表查询
     *
     * @param rows         行数
     * @param order        排序字段
     * @param sort         排序规则
     * @param clazz        返回类型
     * @param queryBuilder 自定义查询规则
     * @throws
     */
    public <T> List<T> list(Integer rows,
                            String order,
                            SortOrder sort,
                            QueryBuilder queryBuilder, Class<T> clazz) throws IOException {
        return this.list(rows, order, sort, queryBuilder, clazz);
    }

    /**
     * 列表查询
     *
     * @param rows         行数
     * @param order        排序字段
     * @param sort         排序规则
     * @param clazz        返回类型
     * @param queryBuilder 自定义查询规则
     * @throws
     */
    public <T> List<T> list(Integer rows,
                            String order,
                            SortOrder sort,
                            String index,
                            QueryBuilder queryBuilder, Class<T> clazz) throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(rows);
        // 排序
        if (StringUtils.isNotBlank(order) && Objects.nonNull(sort)) {
            searchSourceBuilder.sort(order, sort);
        }
        if (Objects.nonNull(queryBuilder)) {
            searchSourceBuilder.query(queryBuilder);
        }
        // SearchRequest
        SearchRequest searchRequest = new SearchRequest();
        if (StringUtils.isNotBlank(index)){
            searchRequest.indices(index);
        }
        searchRequest.source(searchSourceBuilder);
        // 查询ES
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = searchResponse.getHits();
        // 遍历封装列表对象
        List<T> resultList = new ArrayList<>();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            resultList.add(JSON.parseObject(searchHit.getSourceAsString(), clazz));
        }
        return resultList;
    }

    /**
     * 添加文档
     *
     * @param bean
     * @param index 索引
     * @throws
     */
    public IndexResponse add(BaseDomain bean, String index) throws IOException {
        // IndexRequest
        IndexRequest indexRequest = new IndexRequest(index);
        String source = JSON.toJSONString(bean);
        indexRequest.id(bean.getId().toString()).source(source, XContentType.JSON);
        // 操作ES
        return restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
    }

    /**
     * 修改文档
     *
     * @param bean
     * @param index 索引
     * @throws
     */
    public UpdateResponse update(BaseDomain bean, String index) throws IOException {
        // UpdateRequest
        UpdateRequest updateRequest = new UpdateRequest(index, bean.getId().toString());
        updateRequest.doc(JSON.toJSONString(bean), XContentType.JSON);
        // 操作ES
        return restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
    }

    /**
     * 删除文档
     *
     * @param id
     * @param index 索引
     * @throws
     */
    public DeleteResponse deleteById(String id, String index) throws IOException {
        // DeleteRequest
        DeleteRequest deleteRequest = new DeleteRequest(index, id);
        // 操作ES
        return restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
    }

    /**
     * 删除文档
     *
     * @param index 索引
     * @throws
     */
    public AcknowledgedResponse deleteByIndex(String index) throws IOException {
        // DeleteRequest
        DeleteIndexRequest deleteRequest = new DeleteIndexRequest(index);
        // 操作ES
        return restHighLevelClient.indices().delete(deleteRequest, RequestOptions.DEFAULT);
    }

}
